/*********************************************************
 *
 * MDCM
 *
 * Modifications github.com/issakomi
 *
 *********************************************************/

/*=========================================================================

  Program: GDCM (Grassroots DICOM). A DICOM library

  Copyright (c) 2006-2011 Mathieu Malaterre
  All rights reserved.
  See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#ifndef MDCMIPPSORTER_H
#define MDCMIPPSORTER_H

#include "mdcmSorter.h"
#include <vector>
#include <string>

namespace mdcm
{

/**
 * IPPSorter
 * Implement a simple Image Position (Patient) sorter, along the Image
 * Orientation (Patient) direction.
 * This algorithm does NOT support duplicate and will FAIL in case of duplicate
 * IPP.
 * See special note for SetZSpacingTolerance when computing the
 * ZSpacing from the IPP of each DICOM files (default tolerance for consistent
 * spacing is: 1e-6mm)
 *
 * For more information on Spacing, and how it is defined in DICOM, advanced
 * users may refers to:
 *
 * http://gdcm.sourceforge.net/wiki/index.php/Imager_Pixel_Spacing
 *
 * Bug: There are currently a couple of bugs in this implementation:
 *  Gantry Tilt is not considered (always an error)
 *  Application programmer should only sort valid DataSet (eg. MRImageStorage, CTImageStorage, PETImageStorage)
 */
class MDCM_EXPORT IPPSorter : public Sorter
{
public:
  IPPSorter();
  // Main entry point to the sorter.
  // It will execute the filter, option should be set before
  // running this function (SetZSpacingTolerance, ...)
  // Return value indicate if sorting could be achived. Warning this does *NOT* imply
  // that spacing is consistent, it only means the file are sorted according to IPP
  // You should check if ZSpacing is 0 or not to deduce if file are actually a 3D volume
  virtual bool Sort(std::vector<std::string> const & filenames);
  // Functions related to Z-Spacing computation
  // Set to true when sort algorithm should also perform a regular
  // Z-Spacing computation using the Image Position (Patient)
  // Potential reason for failure:
  // 1. ALL slices are taken into account, if one slice if
  // missing then ZSpacing will be set to 0 since the spacing
  // will not be found to be regular along the Series
  void SetComputeZSpacing(bool b) { ComputeZSpacing = b; }
  // 2. Another reason for failure is that that Z-Spacing is only
  // slightly changing (eg 1e-3) along the serie, a human can determine
  // that this is ok and change the tolerance from its default value: 1e-6
  void SetZSpacingTolerance(double tol) { ZTolerance = tol; }
  double GetZSpacingTolerance() const { return ZTolerance; }
  // Sometimes IOP along a series is slightly changing for example:
  // "0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439",
  // "0.999081\\0.0426953\\0.00369275\\-0.0419025\\0.955059\\0.293439",
  // "0.999081\\0.0426952\\0.00369272\\-0.0419025\\0.955059\\0.293439",
  // We need an API to define the tolerance which is allowed. Internally
  // the cross vector of each direction cosines is computed. The tolerance
  // then define the distance in between 1.0 to the dot product of those
  // cross vectors. In a perfect world this dot product is of course 1.0 which
  // imply a DirectionCosines tolerance of exactly 0.0 (default).
  void SetDirectionCosinesTolerance(double tol) { DirCosTolerance = tol; }
  double GetDirectionCosinesTolerance() const { return DirCosTolerance; }
  // Makes the IPPSorter ignore multiple images located at the same position.
  // Only the first occurrence will be kept.
  // DropDuplicatePositions defaults to false.
  void SetDropDuplicatePositions(bool b) { DropDuplicatePositions = b; }
  // Read-only function to provide access to the computed value for the Z-Spacing
  // The ComputeZSpacing must have been set to true before execution of
  // sort algorithm. Call this function *after* calling Sort();
  // Z-Spacing will be 0 on 2 occasions:
  //  Sorting simply failed, potentially duplicate IPP => ZSpacing = 0
  //  ZSpacing could not be computed (Z-Spacing is not constant, or ZTolerance is too low)
  double GetZSpacing() const { return ZSpacing; }

protected:
  bool ComputeZSpacing;
  bool DropDuplicatePositions;
  double ZSpacing;
  double ZTolerance;
  double DirCosTolerance;

};

} // end namespace mdcm

#endif //MDCMIPPSORTER_H
